//
//  Render.m
//  whfdemo001
//
//  Created by 王洪飞 on 2024/6/11.
//

#import "Render.h"
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
#import "GLProgram.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface Render ()
{
    EAGLContext *mContext;
    CAEAGLLayer *mEagllayer;
    GLuint framebuffer;
    GLuint renderbuffer;
    
    GLuint vaoId, eleId;
    GLProgram *programObj;
}

-(void)setupContext;
-(void)setupEagllayer;
-(void)setupFramebuffer;
-(void)setupRenderbuffer;
-(void)draw;
-(void)destory;

-(void)setupProgram;
@end

@implementation Render

+ (Class)layerClass{
    return [CAEAGLLayer class];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setupContext];
        [self setupEagllayer];
        [self setupProgram];
        [self pareData];
    }
    return self;
}


- (void)setupContext{
    mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    [EAGLContext setCurrentContext:mContext];
}

-(void)setupEagllayer {
    mEagllayer = (CAEAGLLayer *)self.layer;
    mEagllayer.opaque = NO;
    mEagllayer.drawableProperties = @{
        kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8,
        kEAGLDrawablePropertyRetainedBacking: @(NO)
    };
}

- (void)setupFramebuffer{
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
    GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
//    if (err != GL_FRAMEBUFFER_COMPLETE) {
//        NSLog(@"check framebuffer error");
//    } else {
//        NSLog(@"check frame buffer successs");
//    }
}

-(void)setupRenderbuffer{
    glGenRenderbuffers(1, &renderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
    [mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:mEagllayer];
    
}

- (void)pareData{
    GLfloat vertices[20] = {
        0.5,0.5,0.0,            1.0, 0.0,
        -0.5,0.5,0.0,            0.0, 0.0,
        0.5,-0.5,0.0,            1.0, 1.0,
        -0.5,-0.5,0.0,           0.0, 1.0,
    };
    
    GLuint indices[6] = {
        0,1,2,1,2,3
    };
    
    glGenVertexArrays(1, &vaoId);
   
    GLuint vboid;
    glGenBuffers(1, &vboid);
    
    glBindVertexArray(vaoId);
    glBindBuffer(GL_ARRAY_BUFFER, vboid);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glGenBuffers(1, &eleId);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eleId);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    GLuint vpos = [programObj attributeIndex:@"vPos"]; //glGetAttribLocation(program, "vPos");
    glVertexAttribPointer(vpos, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
    glEnableVertexAttribArray(vpos);
    
    GLuint vCoord = [programObj attributeIndex:@"vCoord"];
    glVertexAttribPointer(vCoord, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
    glEnableVertexAttribArray(vCoord);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
  
    glBindVertexArray(0);
}

- (void)draw{
    glClearColor(0.5, 0.5, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, self.bounds.size.width, self.bounds.size.height);
    

    glBindVertexArray(vaoId);
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eleId);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
    [mContext presentRenderbuffer:GL_RENDERBUFFER];
    
}

- (void)destory{
    glDeleteRenderbuffers(1, &renderbuffer);
    renderbuffer = 0;
    glDeleteFramebuffers(1, &framebuffer);
    framebuffer = 0;
}

-(void)setupProgram{
    NSString *vShaderStr = @""
    "attribute vec3 vPos;\n"
    "attribute vec2 vCoord;\n"
    "varying vec2 coord;\n"
    "void main(){gl_Position = vec4(vPos,1.0);"
    "coord = vCoord;\n}";
    NSString *fShaderStr = @""
    "precision mediump float;"
    "varying vec2 coord;\n"
    "uniform sampler2D s_texture;\n"
    "void main(){gl_FragColor = vec4(1,1,1,1);}";
//    "void main(){gl_FragColor = texture2D(s_texture,coord);}";
    programObj = [[GLProgram alloc] initWithVertexShaderString:vShaderStr fragmentShaderString:fShaderStr];
    if([programObj link]){
        [programObj use];
        [programObj addAttribute:@"vPos"];
    }
}

- (void)layoutSubviews{

    [self destory];
    [self setupRenderbuffer];
    [self setupFramebuffer];
    [self draw];
}

@end
#pragma clang diagnostic pop
